package com.demo.webapp.ui.displayer;

import java.io.IOException;
import java.util.Locale;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.ng.listener.StrutsListener;
import org.apache.struts2.views.freemarker.FreemarkerManager;
import org.apache.struts2.views.freemarker.ScopesHashModel;

import com.demo.webapp.ui.Component;
import com.demo.webapp.ui.displayer.DisplayerMapping;
import com.demo.webapp.ui.displayer.MessageResourcesDisplayer;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.LocaleProvider;

import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;

/**
 * Freemarker渲染器
 * 模板模式,提供Freemarker作为渲染模板的功能
 * <p>实现preTemplateProcess方法将为模板提供不同数据</p>
 * 
 * @author ryuu.kk
 *
 */
public abstract class FreemarkerDisplayerSupport<T extends Component> extends MessageResourcesDisplayer<T> {

	/**
     * Struts2的freemarker配置管理器
     */
    private static FreemarkerManager freemarkerManager;
    /**
     * freemarker配置
     */
    private Configuration config;
    /**
     * PageContext
     */
    private PageContext pageContext = null;
    /**
     * objectWrapper
     */
    private ObjectWrapper wrapper;
    
    /**
     * 模板的渲染前置处理方法
     * 
     * @param getPageContext() PageContext
     * @param component 组件
     * @param template 模板
     * @param templateModel 模板数据模型
     * @return 操作标志
     */
    protected abstract boolean preTemplateProcess(T component, Template template, TemplateModel templateModel);
    
    /**
     * 对FreemarkerMenuWithStruts2Displayer进行配置
     * @param context ServletContext
     */
    protected static void initialize(ServletContext context) {
    	getFreemarkerManager(context);
    }
    
    /**
     * 调用初始化;
     * 进行menu的渲染。参照{@link net.sf.navigator.taglib.UseMenuDisplayerTag}
     * @see net.sf.navigator.taglib.UseMenuDisplayerTag
     * @param getPageContext() PageContext
     * @param mapping MenuDisplayerMapping
     */
    public void init(PageContext pageContext, DisplayerMapping mapping) {
        super.init(pageContext, mapping);
        this.pageContext = pageContext;
        /*
        if (freemarkerManager == null) {
        	//dispatcher.getConfigurationManager();
            //Dispatcher dispatcher = (Dispatcher) getServletContext().getAttribute(StrutsStatics.SERVLET_DISPATCHER);
        	InitOperations init = new InitOperations();
            Dispatcher dispatcher = init.findDispatcherOnThread();
            if (dispatcher == null) {
                throw new IllegalStateException("Unable to find the Dispatcher in the Servlet Context. Is '" + StrutsListener.class.getName() + "' missing in web.xml?");
            }
            freemarkerManager = dispatcher.getContainer().getInstance(FreemarkerManager.class);
        }
        */
        initialize(getPageContext().getServletContext());
        config = freemarkerManager.getConfiguration(getPageContext().getServletContext());
        wrapper = config.getObjectWrapper();
    }
    
    /**
     * 模板渲染方法
     * 
     * @param component 组件模型
     */
	@Override
	public void display(T component) throws JspException, IOException {
		HttpServletRequest request = getServletRequest();
		HttpServletResponse response = getServletResponse();
		ActionContext ctx = ServletActionContext.getActionContext(request);
		//get template in user page.
		Template template = config.getTemplate(getConfig(), getLocale((Action) ctx.getActionInvocation().getAction()));
		
		Object attrContentType = template.getCustomAttribute("content_type");
        if (attrContentType != null) {
            response.setContentType(attrContentType.toString());
        } else {
            if (freemarkerManager.getNoCharsetInContentType()) {
                response.setContentType(freemarkerManager.getContentType() + "; charset=" + template.getEncoding());
            } else {
                response.setContentType(freemarkerManager.getContentType());
            }
        }
        ScopesHashModel model = (ScopesHashModel) request.getAttribute(FreemarkerManager.ATTR_TEMPLATE_MODEL);
        ServletContext servletContext = request.getSession().getServletContext();
        if (model == null) {
		    model = freemarkerManager.buildTemplateModel(ctx.getValueStack(), ctx.getActionInvocation().getAction(), servletContext, request, response, wrapper);
		}
        if (preTemplateProcess(component, template, model)) {
            try {
                // Process the template
            	// 如果使用 getPageContext().getResponse().getWriter(),在模板中可以使用jsp标签
                template.process(model, getPageContext().getOut());
            } catch (TemplateException e) {
            	e.printStackTrace();
				log.error(e.getMessage());
			} finally {
                //postTemplateProcess(request, response, template, model);
            }
        }		
	}

	/**
	 * 返回HttpServletRequest
	 * 
	 * @return HttpServletRequest
	 */
	protected HttpServletRequest getServletRequest() {
		return getPageContext() == null ? null : (HttpServletRequest) getPageContext().getRequest();
	}
	
	/**
	 * 返回HttpServletResponse
	 * 
	 * @return HttpServletResponse
	 */
	protected HttpServletResponse getServletResponse() {
		return getPageContext() == null ? null : (HttpServletResponse) getPageContext().getResponse();
	}
	
	/**
	 * 返回PageContext
	 * @return PageContext
	 */
	protected PageContext getPageContext() {
		return this.pageContext;
	}
	
	/**
	 * 返回FreemarkerManager对象,如果不存在则创建。
	 * 
	 * @param context ServletContext
	 * @return freemarkerManager对象
	 */
	public static FreemarkerManager getFreemarkerManager(ServletContext context) {
		if (freemarkerManager != null) {
    		return freemarkerManager;
    	}
        Dispatcher dispatcher = (Dispatcher) context.getAttribute(StrutsStatics.SERVLET_DISPATCHER);
        if (dispatcher == null) {
            throw new IllegalStateException("Unable to find the Dispatcher in the Servlet Context. Is '" + StrutsListener.class.getName() + "' missing in web.xml?");
        }
        freemarkerManager = dispatcher.getContainer().getInstance(FreemarkerManager.class);
		return freemarkerManager;
	}
	
	/**
	 * 使用Action的Locale作为优先Locale
	 * @param action Action动作
	 * @return Locale
	 */
	protected Locale getLocale(Action action) {
		if (action instanceof LocaleProvider) {
            return ((LocaleProvider) action).getLocale();
        } else {
            return super.getLocale();
        }
	}
	
	@Override
	public void end(PageContext pageContext) throws JspException {
		//
	}
}
